package com.hzit.hzb.core.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hzit.common.exception.Assert;
import com.hzit.common.result.ResponseEnum;
import com.hzit.common.util.RegexValidateUtils;
import com.hzit.hzb.base.util.JwtUtils;
import com.hzit.hzb.core.pojo.entity.UserAccount;
import com.hzit.hzb.core.pojo.entity.UserInfo;
import com.hzit.hzb.core.mapper.UserInfoMapper;
import com.hzit.hzb.core.pojo.entity.UserLoginRecord;
import com.hzit.hzb.core.pojo.vo.*;
import com.hzit.hzb.core.service.UserAccountService;
import com.hzit.hzb.core.service.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzit.hzb.core.service.UserLoginRecordService;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 用户基本信息 服务实现类
 * </p>
 *
 * @author hbxfwf
 * @since 2024-08-27
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private UserAccountService userAccountService;
	@Autowired
	private UserLoginRecordService recordService;

	@Override
	public void register(RegisterVO vo) {
		// 第一部分：用户信息验证
		// 1.1 对各种数据进行验证
		String mobile = vo.getMobile();         // 手机号
		String code = vo.getCode();             // 验证码
		String password = vo.getPassword();     // 密码
		Assert.notNull(mobile, ResponseEnum.MOBILE_NULL_ERROR);     // 手机号不为空
		Assert.notNull(code,ResponseEnum.CODE_NULL_ERROR);          // 验证码不为空
		Assert.notNull(password,ResponseEnum.PASSWORD_NULL_ERROR);  // 密码不能为空
		Assert.isTrue(RegexValidateUtils.checkCellphone(mobile),ResponseEnum.MOBILE_ERROR);  //手机号不正确
		// 1.2 从redis中得到验证码
		String validCode = (String)redisTemplate.opsForValue().get("hzb:sms:code:" + mobile);   // redis中存放的验证码
		Assert.equals(code,validCode,ResponseEnum.CODE_ERROR);                               // 验证码不相等
		// 1、3 根据手机号查询用户是否存在
		int count = this.count(new QueryWrapper<UserInfo>().eq("mobile", mobile));
		Assert.isTrue(count == 0,ResponseEnum.MOBILE_EXIST_ERROR);                  // 手机号己被注册

		// 第二部分：用户注册
		// 2.1 构造要注册的用户对象
		UserInfo userInfo = new UserInfo();
		userInfo.setMobile(mobile);
		String pwd = SecureUtil.md5(password);
		userInfo.setPassword(pwd);
		userInfo.setHeadImg("https://hzit-bj2402-images.oss-cn-shenzhen.aliyuncs.com/studinfo/2024/08/25/0b92d93e-3772-4d6b-b200-58a677999ab0.jpg");
		userInfo.setStatus(UserInfo.STATUS_NORMAL);     // 正常状态
		userInfo.setUserType(vo.getUserType());         // 用户类型：1：出借人 2：借款人
		this.save(userInfo);
		// 2.2 构造用户账户对象
		UserAccount userAccount = new UserAccount();
		userAccount.setUserId(userInfo.getId());
		userAccountService.save(userAccount);
	}

	/**
	 * 2. 用户登录
	 * @param vo
	 * @return
	 */
	@Override
	public UserInfoVO login(LoginVO vo,String ip) {
		// 第一部分：数据校验
		// 1.1 非空验证
		String mobile = vo.getMobile();
		String password = vo.getPassword();
		Assert.notEmpty(mobile,ResponseEnum.MOBILE_NULL_ERROR); // 手机号不能为空
		Assert.notEmpty(password,ResponseEnum.PASSWORD_NULL_ERROR); // 密码不能为空
		// 1.2 合法性验证
		// 1.2.1 根据用户类型与手机号查询出用户，如果不存在就抛出异常
		UserInfo user = this.getOne(new QueryWrapper<UserInfo>()
				.eq("user_type", vo.getUserType()).eq("mobile", vo.getMobile()));
		Assert.notNull(user,ResponseEnum.LOGIN_MOBILE_ERROR);       // 用户不存在
		// 1.2.2 密码的验证
		Assert.equals(SecureUtil.md5(password),user.getPassword(),ResponseEnum.LOGIN_PASSWORD_ERROR);  // 密码输入有误
		// 1.2.3 判断用户状态是否锁定
		Assert.equals(user.getStatus() ,UserInfo.STATUS_NORMAL,ResponseEnum.LOGIN_LOKED_ERROR);        // 用户被 锁定

		// 第二部分：填充数据
		// 2.1 生成token
		String token = JwtUtils.createToken(user.getId(), user.getName());
		// 2.2 构建一个UserInfoVo对象
		UserInfoVO userInfoVO = new UserInfoVO();
		BeanUtil.copyProperties(user,userInfoVO);
		userInfoVO.setToken(token);
		// 2.3 在用户日志中添加信息
		UserLoginRecord record = new UserLoginRecord();
		record.setUserId(user.getId());
		record.setIp(ip);
		// 2.4 将其保存到数据库中
		recordService.save(record);
		return userInfoVO;
	}

	/**
	 * 条件查询带分页
	 * @param page
	 * @param limit
	 * @param vo
	 * @return
	 */
	@Override
	public IPage<UserInfo> listPage(Integer page, Integer limit, UserInfoQuery vo) {
		// 1. 构造查询对象
		QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
		if(!Objects.isNull(vo)){
			queryWrapper.eq(StrUtil.isNotBlank(vo.getMobile()),"mobile",vo.getMobile())
						.eq(vo.getStatus() != null,"status",vo.getStatus())
						.eq(vo.getUserType() != null,"user_type",vo.getUserType());
		}
		// 2. 开始分页查询
		Page<UserInfo> userInfoPage = this.page(new Page<>(page, limit), queryWrapper);
		// 3. 返回结果
		return userInfoPage;
	}

	/**
	 * 用户加解锁
	 * @param id
	 * @param status
	 */
	@Override
	public void lock(Long id, Integer status) {
		UserInfo userInfo = new UserInfo();
		userInfo.setId(id);
		userInfo.setStatus(status);
		this.updateById(userInfo);
	}

	/**
	 * 校验手机号是否存在
	 * @param mobile
	 * @return
	 */
	@Override
	public boolean checkMobile(String mobile) {
		UserInfo userInfo = this.getOne(new QueryWrapper<UserInfo>().eq("mobile", mobile));
		return userInfo != null;
	}

	/**
	 * 根据登录用户查询用户信息
	 * @param userId
	 * @return
	 */
	@Override
	public UserIndexVO getIndexUserInfo(Long userId) {
		// 1. 根据userId查询用户信息
		UserInfo userInfo = this.getById(userId);
		// 2. 根据userid查询出用户账户信息
		UserAccount userAccount = userAccountService.getOne(new QueryWrapper<UserAccount>().eq("user_id", userId));
		// 3. 根据登录日志信息
		List<UserLoginRecord> list = recordService.list(new QueryWrapper<UserLoginRecord>().eq("user_id", userId).orderByAsc("id"));
		UserLoginRecord loginRecord = list.get(0);
		// 4. 构造一个UserIndexVO对象
		UserIndexVO vo = new UserIndexVO();
		vo.setAmount(userAccount.getAmount());  // 账户余额
		vo.setFreezeAmount(userAccount.getFreezeAmount()); // 冻结金额
		vo.setHeadImg(userInfo.getHeadImg());   // 图像
		vo.setBindStatus(userInfo.getBindStatus()); // 绑定状态
		vo.setLastLoginTime(loginRecord.getUpdateTime());
		vo.setName(userInfo.getName());
		vo.setNickName(userInfo.getNickName());
		vo.setUserId(userId);
		vo.setUserType(userInfo.getUserType()); // 用户类型

		return vo;
	}
}
